package com.ai.controller;

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.dashscope.rag.DashScopeCloudStore;
import com.alibaba.cloud.ai.dashscope.rag.DashScopeDocumentRetriever;
import com.alibaba.cloud.ai.dashscope.rag.DashScopeDocumentRetrieverOptions;
import com.alibaba.cloud.ai.dashscope.rag.DashScopeStoreOptions;
import com.alibaba.cloud.ai.memory.jdbc.MysqlChatMemoryRepository;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.document.Document;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.retrieval.search.DocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.List;

/**
 * @author mis_w
 * @description: TODO
 * @date 2025/9/8 20:29
 */
@RestController
@RequestMapping("/hello/v1")
public class HelloWorldController {

    private static final String DEFAULT_PROMPT = "你是一个博学的智能聊天助手，请根据用户提问回答！";

    private final ChatClient dashScopeChatClient;

    private final DashScopeCloudStore dashScopeCloudStore;

    private final DocumentRetriever documentRetriever;

    // todo：spring ai alibaba中 DashScopeApi 这个没有提供自动装配，需要手动注入(AIDashScopeConfig)
    // 官方已经有人提出issues：https://github.com/springaialibaba/spring-ai-alibaba-website/issues/84
    //public HelloWorldController(DashScopeCloudStore dashScopeCloudStore) {
    //    this.dashScopeCloudStore = dashScopeCloudStore;
    //}

    public HelloWorldController(JdbcTemplate jdbcTemplate, ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {
        // TODO:需要在阿里百炼平台上创建知识库
        DashScopeStoreOptions options = new DashScopeStoreOptions("test");//知识库名称
        DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey("sk-056680f37cbd4c88bb57d78227f931ca").build();

        this.dashScopeCloudStore = new DashScopeCloudStore(dashScopeApi, options);

        // 需要创建好知识库
        this.documentRetriever = new DashScopeDocumentRetriever(dashScopeApi, DashScopeDocumentRetrieverOptions.builder().withIndexName("test").build());

        // 构造 ChatMemoryRepository 和 ChatMemory(增加记忆聊天功能)
        ChatMemoryRepository chatMemoryRepository = MysqlChatMemoryRepository.mysqlBuilder()
                .jdbcTemplate(jdbcTemplate)
                .build();
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .build();

        this.dashScopeChatClient = chatClientBuilder
                .defaultSystem(DEFAULT_PROMPT)
                // 实现 Logger 的 Advisor
                .defaultAdvisors(new SimpleLoggerAdvisor())
                // 注册Advisor
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
                // 设置 ChatClient 中 ChatModel 的 Options 参数
                .defaultOptions(
                        DashScopeChatOptions.builder()
                                .withTopP(0.7)
                                .build()
                )
                .build();

    }


    /**
     * ChatClient 简单调用
     */
    @GetMapping("/simple/chat")
    public String simpleChat(@RequestParam(value = "query", defaultValue = "你好，很高兴认识你，能简单介绍一下自己吗？")String query) {

        //return dashScopeChatClient.prompt(query).call().content();

        // 动态指定options
        return dashScopeChatClient
                .prompt(query)
                .options(DashScopeChatOptions.builder().withTopP(0.8).build())
                .call()
                .content();
    }

    /**
     * ChatClient 流式调用
     */
    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam(value = "query", defaultValue = "你好，很高兴认识你，能简单介绍一下自己吗？")String query,
                                   HttpServletResponse response) {

        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/event-stream");
        return dashScopeChatClient.prompt(query).stream().content();
                //.buffer(3) // 缓冲3个元素，减少碎片化
                //.map(messages -> String.join("", messages))
                //.map(content -> "data: " + content + "\n\n");
    }

    /**
     * 测试阿里百炼知识库相似性检索（ dashScopeCloudStore todo: 需要在百炼平台上创建知识库，构造方法所示：DashScopeStoreOptions）
     * @param message 用户提问
     * @return List<Document>
     */
    @GetMapping("/search/v1")
    public List<Document> store(@RequestParam(value = "message", defaultValue = "What's spring ai") String message) {
        return this.dashScopeCloudStore.similaritySearch(message);
    }

    /**
     * 测试阿里百炼知识库向量检索
     * @param message message
     * @return List<Document>
     */
    @GetMapping("/ai/retrieve")
    public List<Document> retrieve(@RequestParam(value = "message", defaultValue = "What's spring ai") String message) {
        return this.documentRetriever.retrieve(new Query( message));

        //return this.documentRetriever.retrieve(Query.builder().text( message).build());
    }


    /***
     * 记忆对话
     * @param query String
     * @param chatId 上下文对话ID
     * @return String
     */
    @GetMapping("/simple/memory/chat")
    public String simpleChat(@RequestParam(value = "query", defaultValue = "你好，很高兴认识你，能简单介绍一下自己吗？")String query,
                             @RequestParam(value = "chat-id", defaultValue = "1") String chatId) {
        return dashScopeChatClient.prompt(query)
                // 指定上下文对话ID ChatMemory.CONVERSATION_ID(spring-ai-core 依赖不同)
                // 或 AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY
                .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
                .call().content();

    }



}
